package com.jnc.pay.biz.alipay.service;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.jnc.pay.biz.common.service.CommonService;
import com.jnc.pay.biz.common.service.impl.AbstractAliPay;
import com.jnc.pay.biz.common.vo.*;
import com.jnc.pay.constant.AliPayConstant;
import com.jnc.pay.constant.SysConstant;
import com.jnc.pay.core.config.redis.lock.DistributedLock;
import com.jnc.pay.core.model.BaseResp;
import com.jnc.pay.core.model.RespCode;
import com.jnc.pay.util.convert.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;

/**
 * @Auther: jjn
 * @Date: 2020/7/8 11:34
 * @Desc: 支付宝 PC Web
 */
@Slf4j
@Service
public class AliPayPage extends AbstractAliPay {

    @Autowired
    CommonService commonService;
    @Autowired
    DistributedLock locker;

    @Override
    public BaseResp<Map<String, Object>> doPay(PayReq req) {
        AlipayClient alipayClient = new DefaultAlipayClient(AliPayConstant.ALI_GATEWAY,
                req.getAlipayConfig().getAlipayAppId(), req.getAlipayConfig().getPrivateKey(),
                AliPayConstant.PARAM_TYPE, AliPayConstant.CHARSET_TYPE,
                req.getAlipayConfig().getPublicKey(), req.getAlipayConfig().getSignType());

        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setReturnUrl(req.getReturnUrl());
        request.setNotifyUrl(req.getNotifyUrl());

        Map<String, Object> map = fillPayReq(req);
        if(MapUtil.isEmpty(map)){
            return BaseResp.resp(RespCode.ERROR.getCode(), RespCode.ERROR.getDesc(), null);
        }
        map.put("product_code", AliPayConstant.PRODUCT_CODE_PAGE);
        //如果在系统内支付，并且是弹出层支付，建议选择模式二、其他模式会跳出当前iframe
        map.put("qr_pay_mode", 2);
        request.setBizContent(JsonUtil.bean2Json(map));

        String body = "";
        try {
            body = alipayClient.pageExecute(request).getBody();
        } catch (AlipayApiException e) {
            log.error("[Alipay.page] send request to ali failed, error: {}", e);
            return BaseResp.resp(RespCode.ALI_SYS_ERROR.getCode(), "Internal Server Error", null);
        }

        //保存支付订单信息
        log.debug("[Alipay.page] Add ali pay order, model: {}, ali resp: {}", req, body);
        commonService.addTrade(req);

        Map<String, Object> respMap = MapUtil.newHashMap();
        respMap.put("form", body);
        return BaseResp.resp(RespCode.SUCCESS.getCode(), RespCode.SUCCESS.getDesc(), respMap);
    }


    @Override
    public BaseResp<Map<String, Object>> doQuery(QueryReq req) {
        BaseResp<Map<String, Object>> resp = new BaseResp<>();

        AlipayClient alipayClient = new DefaultAlipayClient(AliPayConstant.ALI_GATEWAY,
                req.getAlipayConfig().getAlipayAppId(), req.getAlipayConfig().getPrivateKey(),
                AliPayConstant.PARAM_TYPE, SysConstant.CHARSET_NAME,
                req.getAlipayConfig().getPublicKey(), req.getAlipayConfig().getSignType());
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();

        Map<String, Object> map = MapUtil.newHashMap();
        map.put("out_trade_no", req.getTradeId());
        request.setBizContent(JsonUtil.bean2Json(map));
        String body = "";
        try {
            body = alipayClient.execute(request).getBody();
            log.debug("[Alipay.page.query] resp: {}", body);
            Map respMap = JsonUtil.json2Bean(body, Map.class);
            Map data = MapUtil.get(respMap, "alipay_trade_query_response", Map.class);
            String code = MapUtil.getStr(data, "code");
            String msg = MapUtil.getStr(data, "msg");
            String sub_code = MapUtil.getStr(data, "sub_code");
            String sub_msg = MapUtil.getStr(data, "sub_msg");
            Map<String, Object> result = MapUtil.newHashMap();
            result.put("trade_id", req.getTradeId());
            result.put("app_order_id", req.getAppOrderId());
            if(StrUtil.equals(code, AliPayConstant.CODE_SUCCESS)
                    && StrUtil.equals(sub_code, AliPayConstant.SUB_CODE_SUCCESS)){
                result.put("trade_status", MapUtil.getStr(data, "trade_status"));
                result.put("total_amount", MapUtil.getStr(data, "total_amount"));
                resp.setCode(RespCode.SUCCESS.getCode()).setMsg(RespCode.SUCCESS.getDesc()).setData(result);
            }else{
                resp.setCode(RespCode.ALI_BIZ_ERROR.getCode()).setMsg(sub_msg);
            }
        } catch (AlipayApiException e) {
            log.error("[Alipay.page.query] send request to ali failed, error: {}", e);
            return BaseResp.resp(RespCode.ALI_SYS_ERROR.getCode(), "Internal Server Error", null);
        }
        return resp;
    }

    @Override
    public BaseResp<Map<String, Object>> doRefund(RefundReq req) {
        BaseResp<Map<String, Object>> resp = new BaseResp<>();
        AlipayClient alipayClient = new DefaultAlipayClient(AliPayConstant.ALI_GATEWAY,
                req.getAlipayConfig().getAlipayAppId(), req.getAlipayConfig().getPrivateKey(),
                AliPayConstant.PARAM_TYPE, AliPayConstant.CHARSET_TYPE,
                req.getAlipayConfig().getPublicKey(), req.getAlipayConfig().getSignType());

        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();

        Map<String, Object> map = MapUtil.newHashMap();
        String price = NumberUtil.div(Integer.toString(req.getRefundFee()),
                Integer.toString(100), req.getScale()).toString();
        map.put("out_trade_no", req.getTradeId());
        map.put("trade_no", req.getTradeNo());
        map.put("out_request_no", req.getRefundId());
        map.put("refund_amount", price);

        request.setBizContent(JsonUtil.bean2Json(map));
        String body = "";
        try {
            body = alipayClient.execute(request).getBody();
            log.debug("[Alipay.page.refund] resp: {}", body);
            Map respMap = JsonUtil.json2Bean(body, Map.class);
            Map data = MapUtil.get(respMap, "alipay_trade_refund_response", Map.class);
            String code = MapUtil.getStr(data, "code");
            String msg = MapUtil.getStr(data, "msg");
            Map<String, Object> result = MapUtil.newHashMap();
            result.put("trade_id", req.getTradeId());
            result.put("app_refund_id", req.getAppRefundId());
            if(StrUtil.equals(code, AliPayConstant.CODE_SUCCESS)){
                result.put("refund_id", req.getRefundId());
                result.put("refund_fee", MapUtil.getStr(data, "refund_fee"));
                log.debug("Add alipay page refund order, req: {}", req);
                //生成退款订单数据
                commonService.addRefund(req);
                resp.setCode(RespCode.SUCCESS.getCode()).setMsg(RespCode.SUCCESS.getDesc()).setData(result);
            }else{
                resp.setCode(RespCode.ALI_BIZ_ERROR.getCode()).setMsg(msg);
            }
        }catch (Exception e){
            log.error("[Alipay.page.refund] send request to ali failed, error: {}", e);
            return BaseResp.resp(RespCode.ALI_SYS_ERROR.getCode(), "Internal Server Error", null);
        }

        return resp;
    }

    @Override
    public BaseResp<Map<String, Object>> doRefundQuery(RefundQueryReq req) {
        BaseResp<Map<String, Object>> resp = new BaseResp<>();
        AlipayClient alipayClient = new DefaultAlipayClient(AliPayConstant.ALI_GATEWAY,
                req.getAlipayConfig().getAlipayAppId(), req.getAlipayConfig().getPrivateKey(),
                AliPayConstant.PARAM_TYPE, AliPayConstant.CHARSET_TYPE,
                req.getAlipayConfig().getPublicKey(), req.getAlipayConfig().getSignType());

        AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();

        Map<String, Object> map = MapUtil.newHashMap();
        map.put("out_trade_no", req.getTradeId());
        map.put("trade_no", req.getTradeNo());
        map.put("out_request_no", req.getRefundId());

        request.setBizContent(JsonUtil.bean2Json(map));
        String body = "";
        try {
            body = alipayClient.execute(request).getBody();
            log.debug("[Alipay.page.refund.query] resp: {}", body);
            Map respMap = JsonUtil.json2Bean(body, Map.class);
            Map data = MapUtil.get(respMap, "alipay_trade_fastpay_refund_query_response", Map.class);
            String code = MapUtil.getStr(data, "code");
            String msg = MapUtil.getStr(data, "msg");
            Map<String, Object> result = MapUtil.newHashMap();
            result.put("trade_id", req.getTradeId());
            result.put("app_refund_id", req.getAppRefundId());
            if(StrUtil.equals(code, AliPayConstant.CODE_SUCCESS)){
                result.put("refund_id", req.getRefundId());
                result.put("refund_amount", MapUtil.getStr(data, "refund_amount"));
                result.put("refund_status", MapUtil.getStr(data, "refund_status"));
                resp.setCode(RespCode.SUCCESS.getCode()).setMsg(RespCode.SUCCESS.getDesc()).setData(result);
            }else{
                resp.setCode(RespCode.ALI_BIZ_ERROR.getCode()).setMsg(msg);
            }
        }catch (Exception e){
            log.error("[Alipay.page.refund.query] send request to ali failed, error: {}", e);
            return BaseResp.resp(RespCode.ALI_SYS_ERROR.getCode(), "Internal Server Error", null);
        }
        return resp;
    }
}
